﻿Option Strict On
Option Explicit On
Option Infer On

Imports System
Imports System.Collections.Generic
Imports System.Linq
Imports System.Xml.Linq
Imports System.Xml.XPath
Imports GenDotNet.Task.Common
Imports GenDotNet.Model.Common
Imports <xmlns:orm="http://kadgen.com/KADORM.xsd">
Imports <xmlns:s="http://kadgen.com/Select.xsd">

Public Class CacheSet
   Private name As String
   Public xDocument As XDocument
   Public dataRoot As IRootData

   Public Sub New(ByVal name As String, _
                  ByVal xDocument As XDocument, _
                  ByVal dataRoot As IRootData)
      Me.name = name
      Me.xDocument = xDocument
      Me.dataRoot = dataRoot
   End Sub

   Public Function BuildReturnElement() As XElement
      'Console.WriteLine(<s:Root>
      '                     <<%= XName.Get(name, GetXmlNamespace(s).ToString()) %>>
      '                        <%= dataRoot.GetXList() %>
      '                     </>
      '                  </s:Root>)
      Return <<%= XName.Get(name, GetXmlNamespace(s).ToString()) %>>
                <%= dataRoot.GetXList() %>
             </>
   End Function
End Class


' The generic class forces a different base class for each root
Public Class WrapperBase

   Private Shared mCache As New Dictionary(Of Int32, CacheSet)

   Public Shared Function SetXmlDocument( _
            ByVal category As String, _
            ByVal inputXml As XDocument, _
            ByVal rootData As IRootData, _
            ByRef hash As Int32) _
            As XElement

      If inputXml Is Nothing Then
         Return Nothing
      End If
      hash = (category & inputXml.ToString).GetHashCode()
      Dim cacheset As CacheSet = Nothing
      If mCache.TryGetValue(hash, cacheset) Then
         Return cacheset.BuildReturnElement
      End If
      cacheset = New CacheSet(category, inputXml, rootData)
      mCache.Add(hash, cacheset)
      Console.WriteLine("Return Xml: " & (DateTime.Now.Ticks \ 1000).ToString)
      Return cacheset.BuildReturnElement()
   End Function

   Public Shared Function GetRootData(ByVal hash As Int32) As IRootData
      If mCache.ContainsKey(hash) Then
         Return mCache(hash).dataRoot
      End If
      Return Nothing
   End Function

   'Dim ret = <s:Root>
   '             <s:Objects>
   '                <%= From obj In XDocument...<orm:Object> _
   '                   Select <s:Object <%= obj.Attributes %>/> %>
   '             </s:Objects>
   '             <s:Apis>
   '                <%= From api In XDocument...<orm:Api> _
   '                   Select <s:Api <%= api.Attributes %>/> %>
   '             </s:Apis>
   '             <s:Tables>
   '                <%= From table In XDocument...<orm:Table> _
   '                   Select <s:Table <%= table.Attributes %>/> %>
   '             </s:Tables>
   '             <s:StoredProcs>
   '                <%= From sp In XDocument...<orm:RunSP> _
   '                   Where sp.@Task.EqualsIgnoreCase("Create") _
   '                   Select <s:CreateStoredProc <%= sp.Attributes() %>/> %>
   '                <%= From sp In XDocument...<orm:RunSP> _
   '                   Where sp.@Task.EqualsIgnoreCase("Update") _
   '                   Select <s:UpdateStoredProc <%= sp.Attributes() %>/> %>
   '                <%= From sp In XDocument...<orm:RunSP> _
   '                   Where sp.@Task.EqualsIgnoreCase("Delete") _
   '                   Select <s:DeleteStoredProc <%= sp.Attributes() %>/> %>
   '                <%= From sp In XDocument...<orm:RunSP> _
   '                   Where sp.@Task.EqualsIgnoreCase("Retrieve") _
   '                   Select <s:RetrieveStoredProc <%= sp.Attributes() %>/> %>
   '                <%= From sp In XDocument...<orm:RunSP> _
   '                   Where sp.@Task.EqualsIgnoreCase("RetrieveChild") _
   '                   Select <s:RetrieveChildrenStoredProc <%= sp.Attributes() %>/> %>
   '                <%= From sp In XDocument...<orm:RunSP> _
   '                   Where sp.@Task.EqualsIgnoreCase("RetrieveHierarchy") _
   '                   Select <s:RetrieveHierarchyStoredProc <%= sp.Attributes() %>/> %>
   '                <%= From sp In XDocument...<orm:RunSP> _
   '                   Where sp.@Task.EqualsIgnoreCase("SetSelect") _
   '                   Select <s:RetrieveSetProc <%= sp.Attributes() %>/> %>
   '             </s:StoredProcs>
   '          </s:Root>.ToString()

   'Public Function GetFileName( _
   '         ByVal name As String, _
   '         ByVal category As GeneratorCategory, _
   '         ByVal assemblyFileName As String, _
   '         ByVal templateName As String) _
   '         As String Implements _
   '         LinqGenerator.ILinqGenerator.GetFileName
   '   Dim template = GetTemplate(assemblyFileName, templateName)
   '   Return GetFileName(name, GetCategoryString(category), template)
   'End Function

   'Public Function Generate( _
   '         ByVal assemblyFileName As String, _
   '         ByVal templateName As String, _
   '         ByVal token As Int32) _
   '         As IGenerateReturn _
   '         Implements ILinqGenerator.Generate
   '   Return GetReturn(name, category, 0, assemblyFileName, templateName)
   'End Function

   'Public Function GetOutput( _
   '         ByVal name As String, _
   '         ByVal category As GeneratorCategory, _
   '         ByVal assemblyFileName As String, _
   '         ByVal templateName As String) _
   '         As String _
   '         Implements ILinqGenerator.GetOutput
   '   Return GetOutput(name, GetCategoryString(category), assemblyFileName, templateName)
   'End Function

   'Public Function Generate( _
   '         ByVal name As String, _
   '         ByVal categoryString As String, _
   '         ByVal assemblyFileName As String, _
   '         ByVal templateName As String) _
   '         As IGenerateReturn _
   '         Implements ILinqGenerator.Generate
   '   'Console.WriteLine("Loaded Secondary app domain")
   '   'Dim element = (From x In xDocument...<Api> Where x.@Name = name).FirstOrDefault
   '   ' The zero is temporary
   '   Dim category = CType(System.Enum.Parse(GetType(GeneratorCategory), categoryString), GeneratorCategory)
   '   Return GetReturn(name, category, 0, assemblyFileName, templateName)
   'End Function

   'Public Function GetOutput( _
   '         ByVal name As String, _
   '         ByVal category As String, _
   '         ByVal assemblyFileName As String, _
   '         ByVal templateName As String) _
   '         As String _
   '         Implements ILinqGenerator.GetOutput
   '   'Console.WriteLine("Loaded Secondary app domain")
   '   'Dim element = (From x In xDocument...<orm:RunSP> Where x.@Name = name).FirstOrDefault
   '   Return GetTemplateOutput(GetElement(name, category), assemblyFileName, templateName)
   'End Function

   '#Region "Private methods and properties"
   'Private Function GetElement( _
   '         ByVal name As String, _
   '         ByVal category As String) _
   '         As XElement
   '   Dim elementName = category
   '   If category.EndsWithIgnoreCase("StoredProc") Then
   '      elementName = "RunSP"
   '   End If
   '   ' TODO: THis must be moved across teh metadata boundary as this class should have no dependency on file structure
   '   Return (From x In xDocument.Descendants(GetXmlNamespace(orm) + elementName) _
   '                  Where x.@Name = name).FirstOrDefault
   'End Function

   'Private Function GetFileName( _
   '         ByRef name As String, _
   '         ByVal category As String, _
   '         ByVal template As ITemplate) _
   '         As String
   '   Dim element = GetElement(name, category)
   '   Return GetFileName(element, template)
   'End Function

   'Private Function GetFileName( _
   '         ByRef element As XElement, _
   '         ByVal template As ITemplate) _
   '         As String
   '   Return template.GetFileName(element)
   'End Function

   'Private Function GetTemplateOutput( _
   '        ByVal element As XElement, _
   '        ByVal assemblyFileName As String, _
   '        ByVal templateName As String, _
   '        ByRef fileName As String) _
   '        As String
   '   If element IsNot Nothing Then
   '      Dim template = GetTemplate(assemblyFileName, templateName)
   '      Return GetTemplateOutput(element, template, fileName)
   '   End If
   '   Return Nothing
   'End Function

   '   Private Function GetTemplateOutput( _
   '           ByVal rootdata As IRootData, _
   '           ByVal name As String, _
   '           ByVal template As ITemplate, _
   '           ByRef fileName As String) _
   '           As String
   '      If template IsNot Nothing Then
   '         Return template.Generate(rootdata, name, fileName)
   '      End If
   '      Return Nothing
   '   End Function

   '   Private Function GetReturn( _
   '             ByVal name As String, _
   '             ByVal category As GeneratorCategory, _
   '             ByVal token As Int32, _
   '             ByVal assemblyFileName As String, _
   '             ByVal templateName As String) _
   '             As IGenerateReturn
   '      Dim template = GetTemplate(assemblyFileName, templateName)
   '      Dim fileName As String = String.Empty
   '      Dim rootData As IRootData
   '      Dim cacheset As CacheSet
   '      If token <= 0 Then
   '         cacheset = mCache.Values(0)
   '      Else
   '         cacheset = mCache(token)
   '      End If
   '      Select Case category
   '         Case GeneratorCategory.Object
   '            rootData = cacheset.objectRoot
   '         Case GeneratorCategory.Api
   '            Throw New NotImplementedException("This is a placeholder for future API generation")
   '         Case GeneratorCategory.Table
   '            Throw New NotImplementedException("This is a placeholder for future database generation")
   '         Case Else
   '            rootData = cacheset.storedProcRoot
   '      End Select
   '      Dim output = GetTemplateOutput(rootData, name, template, fileName)
   '      Return New GenerateReturn(output, fileName)
   '   End Function

   '   Private Function GetTemplate( _
   '            ByVal assemblyFileName As String, _
   '            ByVal templateName As String) _
   '            As ITemplate
   '      Dim asm As Reflection.Assembly = Nothing
   '      If Not String.IsNullOrEmpty(assemblyFileName) Then
   '         asm = Reflection.Assembly.LoadFrom(assemblyFileName)
   '         Dim type As Type = Nothing
   '         If asm IsNot Nothing And Not String.IsNullOrEmpty(templateName) Then
   '            type = GetSpecifiedType(asm, templateName)
   '            If type IsNot Nothing Then
   '               Dim obj = Activator.CreateInstance(type)
   '               Return TryCast(obj, ITemplate)
   '            End If
   '         End If
   '      End If
   '      Return Nothing
   '   End Function

   '   Private Shared Function GetSpecifiedType( _
   '            ByVal asm As Reflection.Assembly, _
   '            ByVal name As String) _
   '            As System.Type
   '      Dim type As System.Type = Nothing
   '      ' This is tempoary to test a fix

   '      Try
   '         Dim types = asm.GetTypes()
   '      Catch ex As Exception
   '         Console.WriteLine(ex)
   '      End Try

   '      ' Kind of ugly but it works
   '      For Each testType As System.Type In asm.GetTypes
   '         If testType.Name.EqualsIgnoreCase(name) Then
   '            type = testType
   '            Exit For
   '         End If
   '      Next
   '      Return type
   '   End Function

   '   Private Shared Function GetCategoryString(ByVal category As GeneratorCategory) As String
   '      Dim ret As String = category.ToString()
   '      If ret.EqualsIgnoreCase("StoredProc") Then
   '         ret = "RunSP"
   '      End If
   '      Return ret
   '   End Function
   '#End Region


End Class